package com.example.hello.views.badges;

import com.example.hello.*;
import com.example.hello.POJO.AssignmentPOJO;
import com.example.hello.POJO.BadgePOJO;
import com.example.hello.POJO.TrackPOJO;
import com.example.hello.POJO.UserPOJO;
import com.example.hello.TextField;
import com.example.hello.views.Wireframe1;
import com.example.hello.views.assignments.Assignments;
import com.example.hello.views.tracks.Track;
import com.example.hello.views.tracks.Tracks;
import com.example.hello.views.users.Users;
import com.vaadin.navigator.View;
import com.vaadin.navigator.ViewChangeListener;
import com.vaadin.ui.*;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.ObjectWriter;
import org.codehaus.jackson.type.TypeReference;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;

public class Badges extends VerticalLayout implements View {

    public static final String NAME = "badges";

    private static UserPOJO currentUser;
    private static Set<BadgePOJO> badges = new HashSet<>();

    private VerticalLayout addLayout = new VerticalLayout();
    private HorizontalLayout viewLayout = new HorizontalLayout();

    private HorizontalLayout add = new HorizontalLayout();
    private com.example.hello.Badge[] badgeArray;

    @Override
    public void enter(ViewChangeListener.ViewChangeEvent event) {
        currentUser = ((HelloUI) HelloUI.getCurrent()).getUser();
        if (currentUser == null) currentUser = new UserPOJO();
//        badges = GETBadges("");
//        if (badges == null) badges = new HashSet<>();

        add.setVisible(currentUser.isSiteAdmin());

        /** Redirect to Badge View if needed **/
        String[] parameters = event.getParameters().split("/");
        if (!parameters[0].equals("")) {
            BadgePOJO badge = Badge.GETBadge(parameters[0]);
            if (badge != null) {
                Badge badgeView = new Badge(Badges.NAME + "/" + badge.getEncodedName(), badge);
                getUI().getNavigator().addView(badgeView.NAME, badgeView);
                getUI().getNavigator().navigateTo(badgeView.NAME);
            } else {
                getUI().getNavigator().navigateTo(NAME);
            }
        }
    }

    public Badges() {
        setWidth("100%");
        viewLayout.setWidth("100%");

        currentUser = ((HelloUI) HelloUI.getCurrent()).getUser();
        if (currentUser == null) currentUser = new UserPOJO();
        badges = GETBadges("");
        if (badges == null) badges = new HashSet<>();

        initAdd();
        initDisplay();

        addComponent(addLayout);
        addComponent(viewLayout);
        setComponentAlignment(viewLayout, Alignment.TOP_CENTER);
        setExpandRatio(viewLayout, 1);
    }
    
    private void initAdd() {
        add.setWidth("800px");

        final Heading contentHeading = new Heading("Content", 6);
        final TextField badgeContent = new TextField();
        badgeContent.setWidth("30px");
        final Heading nameHeading = new Heading("Name", 6);
        final TextField badgeName = new TextField();
        badgeName.setWidth("100%");
        final Heading colorHeading = new Heading("Color", 6);
        final ColorPickerArea badgeColor = new ColorPickerArea();
        final BootstrapButton badgeSubmit = new BootstrapButton("Add Badge");
        badgeSubmit.setWidth("120px");

        badgeSubmit.addListener(new Listener() {
            @Override
            public void componentEvent(Event event) {
                BadgePOJO badge = new BadgePOJO(
                        badgeContent.getValue(),
                        badgeName.getEncodedValue(),
                        badgeColor.getColor().getCSS().substring(1)
                );
                addBadge(badge);
                getUI().getNavigator().navigateTo(NAME);
            }
        });
        TextField.enterKeyHandler(badgeSubmit, badgeContent);
        TextField.enterKeyHandler(badgeSubmit, badgeName);

        BootstrapButton addBadges = new BootstrapButton("Add 10 Badges");
        addBadges.addListener(new Listener() {
            @Override
            public void componentEvent(Event event) {
                for (int j = 0; j < 10; j++) {
                    BadgePOJO badge = new BadgePOJO();
                    Random rand = new Random();
                    // get random content
                    char content = 0;
                    int i = rand.nextInt(26) + 1;
                    if (i > 0 && i < 27) content = (char) (i + 64);

                    // get random color
                    String color = "";
                    for (i = 0; i < 6; i++) color += Integer.toHexString(rand.nextInt(16));

                    // add the values to the new badge
                    badge.setContent(String.valueOf(content));
                    badge.setName(String.valueOf(content));
                    badge.setColor(color);

                    addBadge(badge);
                }
                getUI().getNavigator().navigateTo(NAME);
            }
        });

        add.addComponents(
                contentHeading, new HSpacer(5), badgeContent,
                new HSpacer(20),
                nameHeading, new HSpacer(5), badgeName,
                new HSpacer(20),
                colorHeading, new HSpacer(5), badgeColor,
                new HSpacer(20),
                badgeSubmit,
                new HSpacer(20),
                addBadges
        );

        add.setComponentAlignment(contentHeading, Alignment.MIDDLE_LEFT);
        add.setComponentAlignment(badgeContent, Alignment.MIDDLE_LEFT);
        add.setComponentAlignment(nameHeading, Alignment.MIDDLE_LEFT);
        add.setComponentAlignment(badgeName, Alignment.MIDDLE_LEFT);
        add.setComponentAlignment(colorHeading, Alignment.MIDDLE_LEFT);
        add.setComponentAlignment(badgeColor, Alignment.MIDDLE_LEFT);
        add.setExpandRatio(badgeName, 1);

        addLayout.addComponents(new VSpacer(10), add, new VSpacer(20));
        addLayout.setComponentAlignment(add, Alignment.MIDDLE_CENTER);
        addLayout.setExpandRatio(add, 1);
    }
    
    private void initDisplay() {
        VerticalLayout badgeLayout = new VerticalLayout();
        badgeLayout.setWidth("100%");

        // this creates the placement for each badge
        int[] r = new int[HelloUI.SIZE / 135 - 1];
        int q = badges.size() % r.length;
        for (int i = 0; i < r.length; i++) {
            r[i] = badges.size() / r.length + ((q - i > 0) ? 1 : 0);
        }

        HorizontalLayout tmp = new HorizontalLayout();
        tmp.setWidth(r.length * 135, Unit.PIXELS);
        GridLayout grid = new GridLayout();
        grid.setColumns(r.length);
        grid.setWidth(r.length * 135, Unit.PIXELS);
        if (r[0] == 0) {
            grid.setRows(1);
        } else {
            grid.setRows(r[0]);
            grid.setHeight(r[0] * 40, Unit.PIXELS);
        }

        badgeArray = new com.example.hello.Badge[badges.size()];
        Iterator<BadgePOJO> itr = badges.iterator();
        int x = 0;
        while (itr.hasNext()) badgeArray[x++] = itr.next().createBadge();
        Arrays.sort(badgeArray);

        com.example.hello.Badge[] tmp2 = new com.example.hello.Badge[badgeArray.length];

        // fill a r.length x max(r[i]) grid from the left-most column
        // top-down, moving towards the right-most column
        int t = 0;
        for (int i = 0; i < r.length; i++) {
            for (int j = 0; j < r[i]; j++) {
                tmp2[i + j * r.length] = badgeArray[t + j];
            }
            t += r[i];
        }
        badgeArray = tmp2;

        int index = 0;
        final int indexend = badgeArray.length;
        while (index != indexend) {
            final com.example.hello.Badge badge = badgeArray[index];
            Label label = new Label(badge.getName());
            label.setWidth("100px");

            HorizontalLayout tmp3 = new HorizontalLayout(badge, new HSpacer(5), label);
            tmp3.setWidth("135px");
            tmp3.setComponentAlignment(label, Alignment.MIDDLE_LEFT);
            tmp3.setExpandRatio(label, 1);

            grid.addComponent(tmp3, index % r.length, index++ / r.length);
            grid.setComponentAlignment(tmp3, Alignment.TOP_LEFT);
        }
        badgeLayout.addComponent(grid);
        badgeLayout.setComponentAlignment(grid, Alignment.TOP_CENTER);

        // add cell table for display
        viewLayout.addComponent(badgeLayout);
        viewLayout.setComponentAlignment(badgeLayout, Alignment.TOP_CENTER);
        viewLayout.setExpandRatio(badgeLayout, 1);
    }

    public static Set<BadgePOJO> GETBadges(String query) {
        Set<BadgePOJO> badges = new HashSet<>();
        try {
            String json = HttpRequest.GET(Badges.NAME + query);
            ObjectMapper mapper = new ObjectMapper();
            badges = mapper.readValue(json, new TypeReference<Set<BadgePOJO>>() {
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
        return badges;
    }

    public static Set<BadgePOJO> getBadges() {
        return badges;
    }

    public static void setBadges(Set<BadgePOJO> badges) {
        Badges.badges = badges;
    }

    public static boolean addBadge(BadgePOJO badge) {
        // post a badge to get an _id
        if (!HttpRequest.executePost(NAME, badge.toJSON())) return false;

        // get the badge with _id attached
        badge = Badge.GETBadge(badge.getEncodedName());
        if (!badges.contains(badge)) badges.add(badge);

        // create the View with the badge
        Badge badgeView = new Badge(Badges.NAME + "/" + badge.getEncodedName(), badge);
        HelloUI.getCurrent().getNavigator().addView(badgeView.NAME, badgeView);

        return true;
    }

    public static boolean removeBadge(BadgePOJO badge) {
        // get all linked resources and update or relocate
        List<AssignmentPOJO> assignments = Assignments.GETAssignments("?badge=" + badge.getEncodedName());
        Set<TrackPOJO> tracks = Tracks.GETTracks("?track=" + badge.getEncodedName());
        Set<UserPOJO> users = Users.GETUsers("?badge=" + badge.getEncodedName());
        for (AssignmentPOJO assignment : assignments) {
            if (assignment.removeBadge(badge.getEncodedName())) assignment.update();
        }
        for (TrackPOJO track : tracks) {
            if (track.removeBadge(badge.getEncodedName())) track.update();
        }
        for (UserPOJO user : users) {
            if (user.removeBadge(badge.getEncodedName())) user.update();
        }

        // delete the badge
        HttpRequest.executeDelete(NAME + "/" + badge.getEncodedName());
        HelloUI.getCurrent().getNavigator().removeView(NAME + "/" + badge.getEncodedName());

        return badges.remove(badge);
    }

    public static boolean hasBadge(BadgePOJO badge) {
        return badges.contains(badge);
    }

}